package com.kai.admin.security.service;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kai.admin.security.constants.SecurityConstants;
import com.kai.admin.data.SourceUser;
import com.kai.admin.util.CacheKeyRegistryUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * token 服务
 * </p>
 *
 * @author weijk
 * @since 2023/6/29
 */
@Service
public class SecurityTokenService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 生成并保存 token
     *
     * @param sourceUser 当前用户
     * @return token
     */
    public String generateAndSaveToken(SourceUser sourceUser) {
        String accessToken = IdUtil.fastSimpleUUID();
        saveToken(sourceUser, accessToken);

        return accessToken;
    }

    /**
     * 刷新 token
     *
     * @param sourceUser 当前用户
     * @param accessToken token
     */
    public void refreshToken(SourceUser sourceUser, String accessToken) {
        saveToken(sourceUser, accessToken);
    }

    /**
     * 保存 token
     *
     * @param sourceUser 当前用户
     * @param accessToken token
     */
    private void saveToken(SourceUser sourceUser, String accessToken) {
        LocalDateTime expirationTime = LocalDateTimeUtil.offset(LocalDateTime.now(), SecurityConstants.TOKEN_EXPIRATION_TIME, ChronoUnit.HOURS);
        sourceUser.setExpirationTime(expirationTime);
        redisTemplate.opsForValue().set(CacheKeyRegistryUtil.getTokenKey(accessToken), JSON.toJSONString(sourceUser), SecurityConstants.TOKEN_DESTRUCTION_TIME, TimeUnit.SECONDS);
    }

    /**
     * 删除 token
     *
     * @param accessToken token
     */
    public void deleteToken(String accessToken) {
        redisTemplate.delete(CacheKeyRegistryUtil.getTokenKey(accessToken));
    }

    /**
     * 校验 token，token 不存在返回 null
     *
     * @param accessToken token
     * @return 当前用户信息
     */
    public SourceUser checkToken(String accessToken) {
        String user = redisTemplate.opsForValue().get(CacheKeyRegistryUtil.getTokenKey(accessToken));
        if (StringUtils.isBlank(user)) {
            return null;
        }

        SourceUser sourceUser = JSONObject.parseObject(user, SourceUser.class);
        checkExpirationTime(sourceUser, accessToken);

        return sourceUser;
    }

    /**
     * 检查过期时间，过期则刷新 token
     *
     * @param sourceUser 用户信息
     * @param accessToken token
     */
    private void checkExpirationTime(SourceUser sourceUser, String accessToken) {
        LocalDateTime expirationTime = sourceUser.getExpirationTime();
        if (LocalDateTime.now().isAfter(expirationTime)) {
            refreshToken(sourceUser, accessToken);
        }
    }
}
